<?

/**
 * 购物车类
 */

class Cart extends Base {

	//购物车最大记录数
	public $max_row = 50;

	//购物车每条记录（商品）最大购买数量
	public $max_qty = 100;

	//购物车保存时间，2592000 => 30天
	public $expire = 2592000;

	//匿名购物车ID
	private $_default_cart_id = '';

	//会员购物车ID
	private $_user_cart_id = '';

	//购物车记录（row_id为键名的二维数组）
	private $_items = array();

	protected $_valid = array('max_row', 'max_qty', 'expire');

	public function __construct()
	{
		if ( ! session_id())
		{
			session_start();
		}

		$user_id = intval($this->_get_user_id());

		$this->_default_cart_id = 'default_cart_'.session_id();
		$this->_user_cart_id = $user_id > 0 ? 'user_cart_'.$user_id : '';
	}

	public function init()
	{
		$data = array();

		$default_cart_data = $this->_get($this->_default_cart_id);
		//如果用户已经登录，需要将匿名购物车内容转移到用户购物车中
		if ($this->_user_cart_id)
		{
			$user_cart_data = $this->_get($this->_user_cart_id);
			if ($this->default_cart_data)
			{
				//清空默认购物车数据
				if (FALSE === $this->_save($this->_default_cart_id, serialize(''), $this->expire, time()))
				{
					$this->set_error('保存购物车失败！');
					return FALSE;
				}
				//转移默认购物车数据到会员购物车数据
				$data = $this->_merger($user_cart_data, $default_cart_data);
			}
		}
		else
		{
			$data = $default_cart_data;
		}

		if ($data)
		{
			$data = unserialize($data);

			if ($data && time() < $data['time'] + $data['expire'])
			{
				$this->_items = $data['items'];
				//刷新，去除已经过期的记录
				$this->refresh();
			}
		}

		return TRUE;
	}

	/**
	 * 加入购物车
	 * @param array $item 记录数组
	 * @return string 返回购物车记录ID
	 */
	public function add($item)
	{
		$default = array(
			'id' => 0, //商品id
			'item' => '', //商品货号
			'name' => '', //商品名称
			'price' => 0, //商品价格
			'qty' => 1, //商品数量
			'options' => array(), //其他参数，数组，用来自定义一些内容
			'time' => 0, //加入购物车时间
			'expire' => 0, //过期时间，秒
			'min_qty' => 1, //最少购买量
			'max_qty' => 100, //最多购买量
			'update_able' => TRUE, //是否可以修改，包含增加、减少、删除
			'delete_able' => TRUE, //是否允许删除
			'flag' => 0 //标识符号，可以自定义来标识这条记录来源，比如秒杀，抢购等
		);

		$item = array_merge($default, $item);

		$time = time();
		$item['id'] = trim($item['id']);
		$item['item'] = trim($item['item']);
		$item['name'] = trim($item['name']);
		$item['price'] = floatval($item['price']);
		$item['qty'] = intval($item['qty']) > 0 ? intval($item['qty']) : 1;
		$item['options'] = (array)$item['options'];
		$item['time'] = $time;
		$item['expire'] = intval($item['expire']) > 0 ? intval($item['expire']) : 0;
		$item['min_qty'] = intval($item['min_qty']) > 0 ? intval($item['min_qty']) : 1;
		$item['max_qty'] = intval($item['max_qty']) > 0 ? intval($item['max_qty']) : 1;
		$item['update_able'] = (boolean)$item['update_able'];
		$item['delete_able'] = $item['update_able'] === FALSE ? (boolean)$item['delete_able'] : TRUE;
		$item['flag'] = intval($item['flag']) > 0 ? intval($item['flag']) : 0;

		//货号和标识符组成购物车记录ID
		$row_id = $this->_get_row_id($item);

		$cart_item = $this->fetch($row_id);
		//如果购物车有这个记录
		if ($cart_item)
		{
			if ($cart_item['update_able'] === TRUE)
			{
				$cart_item['id'] = $item['id'];
				$cart_item['name'] = $item['name'];
				$cart_item['price'] = $item['price'];
				$cart_item['options'] = $item['options'];
				$cart_item['time'] = $time;
				$cart_item['expire'] = $item['expire'];
				$cart_item['min_qty'] = $item['min_qty'];
				$cart_item['max_qty'] = $item['max_qty'];
				$cart_item['delete_able'] = $item['delete_able'];
				$cart_item['qty'] = min(++$cart_item['qty'], $cart_item['max_qty'], $this->max_qty);
			}

			$item = $cart_item;
		}
		else
		{
			//判断购物车容量大小
			if (count($this->_items) >= $this->max_row)
			{
				$this->set_error('购物车已满！');
				return FALSE;
			}
		}

		$this->_items[$row_id] = $item;

		return $row_id;

	}

	/**
	 * 刷新购物车，删除已经过期的记录
	 * @return object 返回$this
	 */
	public function refresh()
	{
		if ($this->_items)
		{
			$time = time();
			foreach ($this->_items as $k => $v)
			{
				if ($v['expire'] > 0 && $time > $v['time'] + $v['expire'])
				{
					unset($this->_items[$k]);
				}
			}
		}

		return $this;
	}

	/**
	 * 返回购物车内容
	 * @return array 购物车所有内容
	 */
	public function content()
	{
		return $this->_items;
	}

	/**
	 * 判断某条购物车记录是否存在
	 * @param string $row_id 记录id
	 * @return boolean 返回是否存在，TRUE or FALSE
	 */
	public function exists($row_id)
	{
		return isset($this->_items[$row_id]);
	}

	/**
	 * 根据记录id获取某条购物车记录详细信息
	 * @param string $row_id 记录id
	 * @return mixed 存在记录则返回记录数据（Array），否则返回FALSE
	 */
	public function fetch($row_id)
	{
		return $this->exists($row_id) ? $this->_items[$row_id] : FALSE;
	}

	/**
	 * 增加购物车记录的商品数量
	 * @param string $row_id 记录id
	 * @param integer $num 增加的数量
	 * @return boolean 返回是否操作成功，TRUE or FALSE
	 */
	public function increase($row_id, $num = 1)
	{
		if ($this->exists($row_id))
		{
			if ( ! $this->_items[$row_id]['update_enable'])
			{
				$this->set_error('此记录不允许修改！');
				return FALSE;
			}
			elseif ($this->_items[$row_id]['qty'] >= min($this->_items[$row_id]['max_qty'], $this->max_qty))
			{
				$this->set_error('已经达到最大数量限制！');
				return FALSE;
			}

			$this->_items[$row_id]['time'] = time();
			$this->_items[$row_id]['qty'] += $num;
			$this->_items[$row_id]['qty'] = min($this->_items[$row_id]['qty'], $this->_items[$row_id]['max_qty']);
			return TRUE;
		}

		return FALSE;
	}

	/**
	 * 减少购物车记录的商品数量
	 * @param string $row_id 记录id
	 * @param integer $num 增加的数量
	 * @return boolean 返回是否操作成功，TRUE or FALSE
	 */
	public function decrease($row_id, $num = 1)
	{
		if ($this->exists($row_id))
		{
			if ( ! $this->_items[$row_id]['update_able'])
			{
				$this->set_error('此记录不允许修改！');
				return FALSE;
			}
			elseif ($this->_items[$row_id]['qty'] <= max($this->_items[$row_id]['min_qty'], 1))
			{
				$this->set_error('已经达到最小数量限制！');
				return FALSE;
			}

			$this->_items[$row_id]['time'] = time();
			$this->_items[$row_id]['qty'] -= $num;
			$this->_items[$row_id]['qty'] = max($this->_items[$row_id]['qty'], $this->_items[$row_id]['min_qty']);
			return TRUE;
		}

		return FALSE;
	}

	/**
	 * 删除某条购物车记录
	 * @param string $row_id 记录id
	 * @return boolean 返回是否操作成功，TRUE or FALSE
	 */
	public function remove($row_id)
	{
		$item = $this->fetch($row_id);
		if ($item && $item['delete_able'])
		{
			unset($this->_items[$row_id]);
			return TRUE;
		}
		
		$this->set_error('此记录不允许删除！');
		return FALSE;
	}

	/**
	 * 销毁/清空购物车
	 * @return boolean 返回是否操作成功，TRUE or FALSE
	 */
	public function destroy()
	{
		$this->_items = array();
		return TRUE;
	}

	/**
	 * 保存购物车
	 * @return boolean 返回是否操作成功，TRUE or FALSE
	 */
	public function save()
	{
		$id = $this->_user_cart_id ? $this->_user_cart_id : $this->_default_cart_id;

		$time = time();

		$data = array(
			'items' => $this->_items,
			'time' => $time,
			'expire' => $this->expire
		);

		return $this->_save($id, serialize($data), $this->expire, $time);
	}

	/**
	 * 返回购物车记录ID
	 * @param array $item 要加入购物车的商品数据
	 * @return string 购物车记录ID
	 */
	private function _get_row_id($item)
	{
		return md5($item['item'].'=========================='.$item['flag']);
	}

	/**
	 * 转移默认购物车数据到会员购物车
	 * @param array $user 会员购物车数据
	 * @param array $default 默认购物车数据
	 * @return array 返回合并后的数据
	 */
	private function _merger($user, $default)
	{
		if ($default)
		{
			foreach ($default as $row_id => $item)
			{
				if (isset($user[$row_id]))
				{
					$qty = $item['qty'] + $user[$row_id]['qty'];
					$item = $item['time'] >= $user[$row_id]['time'] ? $item : $user[$row_id];
					$item['qty'] = min($qty, $item['max_qty'], $this->max_qty);
				}
				
				$user[$row_id] = $item;
			}
		}

		return $user;
	}

	/**
	 * 根据键返回数据
	 * @param string $id 键
	 * @return string 数据
	 */
	private function _get($id)
	{
		$data = '';

		//DOIT
		//返回键名为$id的数据
		
		$data = isset($_COOKIE[$id]) ? $_COOKIE[$id] : '';

		return $data;
	}

	/**
	 * 保存购物车数据
	 * @param string $id 键
	 * @param string $data 数据
	 * @param integer $expire 过期时间，保存多久（秒）
	 * @param integer $now 现在时间（时间戳）
	 * @return boolean 是否成功
	 */
	private function _save($id, $data, $expire, $now)
	{
		//DOIT
		//保存键名为$id,键值为$data数据到……

		return setcookie($id, $data, $now + $expire);
	}

	private function _get_user_id()
	{
		$user_id = 0;
		//DOIT
		//获取登录用户ID
		
		return $user_id;
	}

	public function set_max_row($max_row)
	{
		$this->max_row = intval($max_row) > 0 ? intval($max_row) : 0;
	}

	public function set_max_qty($max_qty)
	{
		$this->max_qty = intval($max_qty) > 0 ? intval($max_qty) : 0;
	}

	public function set_expire($expire)
	{
		$this->expire = intval($expire) > 0 ? intval($expire) : 0;
	}

}